home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 1.iso / ARGONET / PD / GAMES / WIMPGAME / MINES2.ZIP / !Mines / c / Hint < prev    next >
Text File  |  1995-05-03  |  25KB  |  785 lines

  1. #include "MineHeader.h"
  2. #include "Mines.h"
  3. #include "Mouse.h"
  4.  
  5. #define in_playground(x,y) (((x)>=0) && ((x)<XMAX) && ((y)>=0) && ((y)<YMAX))
  6.  
  7. int move_wrong(int x0,int y0)
  8. {
  9.     return ((feld[x0][y0] & MARK) && !(feld[x0][y0] & MINE));
  10. }
  11.  
  12. int move_obvious(int x0,int y0)
  13. {
  14.     /* ein Zug ist offensichtlich, wenn die Anzahl der Nachbarfelder
  15.     ** gleich der Anzahl der Nachbarminen ist ( dann bekommt jedes
  16.     ** Nachbarfeld eine Marke ), oder wenn die Anzahl der Nachbarminen
  17.     ** gleich der Anzahl der Nachbarmarken ist ( dann sind alle ver-
  18.     ** deckten Felder leer.
  19.     */
  20.     int mines=0,marks=0,unknown=0,d;
  21.     if (feld[x0][y0] & CLOSED) return(FALSE);
  22.     for (d=0;d<8;d++)
  23.     {
  24.         int x1=x0+off[d][0],y1=y0+off[d][1];
  25.         if (in_playground(x1,y1))
  26.         {
  27.             register char f=feld[x1][y1];
  28.             if (f & CLOSED) {if (f & MARK) marks++; else unknown++;};
  29.             if (f & MINE) mines++;
  30.         }
  31.     }
  32.     if ((unknown!=0) && ((marks==mines) || (marks+unknown==mines))) return(TRUE);
  33.     return(FALSE);
  34. }
  35.  
  36. /* Variablen fuer den Algorithmus */
  37. typedef struct {char x,y,domain;int test;} border_typ;
  38. border_typ *border_arr,*border_anz,*last_border_arr=0,*last_border_anz;
  39. int *minmax,*lastminmax,unnecessary_hints;
  40. /* Makros fuer den Zugriff auf minmax und lastminmax
  41. ** (ich weiss nicht, wie man Zeiger auf mehrdimensionale Felder
  42. ** vereinbart, so dass es kein Feld von Zeigern ist).
  43. ** int *minmax[3]; ?
  44. */
  45. #define min(domain) minmax[(domain)*2]
  46. #define max(domain) minmax[(domain)*2+1]
  47. #define last_min(last_domain) lastminmax[(last_domain)*2]
  48. #define last_max(last_domain) lastminmax[(last_domain)*2+1]
  49.  
  50. /* Variablen fuer die WIMP-Unterstuetzung */
  51. window_data hint_window,hint_choose_window;
  52. char clue_msg1[]="      You can still make some clues !       ";
  53. char clue_msg2[]="                 Give one ?                 ";
  54. char hint_msg1[]="           You don't need a hint !          ";
  55. char hint_msg2[]="                Give anyway ?               ";
  56. char err_msg1[] ="             You made a mistake !           ";
  57. char err_msg2[] ="                  Show it ?                 ";
  58. int hint_index,hint_choose=FALSE;
  59.  
  60. int find_next(int *x,int *y)
  61. {
  62.     /*
  63.     ** sucht das naechste Feld, dass sowohl bedeckte als auch unbedeckte
  64.     ** Felder als Nachbarn hat und selbst bedeckt ist, aber keine Marke
  65.     ** hat, kurz gesagt: am Rand ist.
  66.     */
  67.     int closed_neighbors,open_neighbors,d;
  68.     do {
  69.         open_neighbors=0;closed_neighbors=0;
  70.         *x+=1;if (*x>=XMAX) {*x=0;*y+=1;};
  71.         if (*y<YMAX)
  72.             for (d=0;d<8;d++)
  73.             {
  74.                 int newx=*x+off[d][0],newy=*y+off[d][1];
  75.                 if (in_playground(newx,newy))
  76.                     {if (feld[newx][newy] & CLOSED) closed_neighbors++;
  77.                         else open_neighbors++;};
  78.             }
  79.     } while ((*y<YMAX) && ((feld[*x][*y] & MARK) || !(feld[*x][*y] & CLOSED) || (open_neighbors==0) || (closed_neighbors==0)));
  80.     if (*y>=YMAX) return FALSE;
  81.     return TRUE;
  82. }
  83.  
  84. /* ===============================================================
  85. ** =       Routinen zur Sortierung in Bereiche                   =
  86. ** ===============================================================
  87. */
  88.  
  89. border_typ *find_field(int x,int y,border_typ *i)
  90. {
  91.     /* sucht ein Feld mit Koordinaten (x/y) in border_arr
  92.     ** ab Position i. Gibt eine Pointer auf das passende
  93.     ** Element zurueck, sonst 0.
  94.     */
  95.     while ((i<border_anz) && ((i->x!=x) || (i->y!=y))) i++;
  96.     if ((x==i->x) && (y==i->y) && (i<border_anz)) return i;
  97.     return 0;
  98. }
  99.  
  100. border_typ *exchange_field(border_typ *end_domain,border_typ *i,char domain)
  101. {
  102.     /* sortiert den Inhalt von i an das Ende des Bereiches,
  103.     ** vergroessert den Bereich um eins und gibt den neuen
  104.     ** Zeiger auf das Ende des Bereiches zurueck.
  105.     */
  106.     border_typ d;
  107.     if (i==0) return end_domain;
  108.     end_domain++;
  109.     d=*end_domain;*end_domain=*i;*i=d;
  110.     end_domain->domain=domain;
  111.     return end_domain;
  112. }
  113.  
  114. border_typ *find_neighbors(int x0,int y0,border_typ *end_domain,char domain)
  115. {
  116.     /* sortiert alle Nachbarn des Feldes (x0/y0) an des Ende des
  117.     ** Bereiches und gibt den neuen Zeiger auf das Bereichsende
  118.     ** zurueck.
  119.     */
  120.     char d;
  121.     for (d=0;d<8;d++)
  122.        end_domain=exchange_field(end_domain,
  123.                   find_field(x0+off[d][0],y0+off[d][1],end_domain+1),
  124.                   domain);
  125.     return end_domain;
  126. }
  127.  
  128. border_typ *find_domains(border_typ *border,char domain)
  129. {
  130.     /* Sortiert alle zusammengehoerigen Felder ab border
  131.     ** in einen Bereich mit der Nummer domain. Dazu werden
  132.     ** alle Nachbarfelder offener Nachbarfelder zusammengesucht.
  133.     */
  134.     char d;
  135.     border_typ *end_domain=border;
  136.     border->domain=domain;
  137.     do {
  138.         for (d=0;d<8;d++)
  139.         {
  140.             int x=border->x+off[d][0],y=border->y+off[d][1];
  141.             if (in_playground(x,y) && !(feld[x][y] & CLOSED))
  142.                 end_domain=find_neighbors(x,y,end_domain,domain);
  143.         }
  144.         border++;
  145.     } while ((border->domain==domain) && (border<border_anz));
  146.     return end_domain+1;
  147. }
  148.  
  149. /* ========================================================
  150. ** =      Routine zur Optimierung des Abbruchtestes       =
  151. ** ========================================================
  152. */
  153.  
  154. #define F0 0X00000001
  155. #define F1 0X00000010
  156. #define F2 0X00000100
  157. #define F3 0X00001000
  158. #define F4 0X00010000
  159. #define F5 0X00100000
  160. #define F6 0X01000000
  161. #define F7 0X10000000
  162.  
  163. void find_testmode(border_typ *border,char domain)
  164. {
  165.     /* versieht jedes Feld mit einer Maske, die fuer jede Richtung
  166.     ** ein Bit enthaelt, das anzeigt, ob ein offenes Nachbarfeld
  167.     ** in dieser Richtung genau verglichen werden kann oder nicht.
  168.     ** Es kann genau verglichen werden, wenn keines seiner Nachbar-
  169.     ** felder mehr veraendert werden kann, d.h. sich kein Nachbar-
  170.     ** feld spaeter in dem Bereich befindet.
  171.     */
  172.     os_error fielddouble = { 0 , "Field Double"} ;
  173.     while ((border->domain==domain) && (border<border_anz))
  174.     {
  175.         border_typ *ptr=border+1;
  176.         char x,y;
  177.         x=border->x;y=border->y;border->test=0;
  178.         while ((ptr->domain==domain) && (ptr<border_anz))
  179.         {
  180.             char x1=ptr->x,y1=ptr->y;
  181.             if (y1+2==y)
  182.             {
  183.                 if (x1+2==x) border->test+=F0;
  184.                 if (x1+1==x) border->test+=F0+F1;
  185.                 if (x1==x)   border->test+=F0+F1+F2;
  186.                 if (x1==x+1) border->test+=F1+F2;
  187.                 if (x1==x+2) border->test+=F2;
  188.             }
  189.             if (y1+1==y)
  190.             {
  191.                 if (x1+2==x) border->test+=F0+F3;
  192.                 if (x1+1==x) border->test+=F0+F1+F3;
  193.                 if (x1==x)   border->test+=F0+F1+F2+F3+F4;
  194.                 if (x1==x+1) border->test+=F1+F2+F4;
  195.                 if (x1==x+2) border->test+=F2+F4;
  196.             }
  197.             if (y1==y)
  198.             {
  199.                 if (x1+2==x) border->test+=F0+F3+F5;
  200.                 if (x1+1==x) border->test+=F0+F1+F3+F5+F6;
  201.                 if (x1==x) wimp_report_error(&fielddouble,2,"Mines !");
  202.                 if (x1==x+1) border->test+=F1+F2+F4+F6+F7;
  203.                 if (x1==x+2) border->test+=F2+F4+F7;
  204.             }
  205.             if (y1==y+1)
  206.             {
  207.                 if (x1+2==x) border->test+=F3+F5;
  208.                 if (x1+1==x) border->test+=F3+F5+F6;
  209.                 if (x1==x)   border->test+=F3+F4+F5+F6+F7;
  210.                 if (x1==x+1) border->test+=F4+F6+F7;
  211.                 if (x1==x+2) border->test+=F4+F7;
  212.             }
  213.             if (y1==y+2)
  214.             {
  215.                 if (x1+2==x) border->test+=F5;
  216.                 if (x1+1==x) border->test+=F5+F6;
  217.                 if (x1==x)   border->test+=F5+F6+F7;
  218.                 if (x1==x+1) border->test+=F6+F7;
  219.                 if (x1==x+2) border->test+=F7;
  220.             }
  221.             ptr++;
  222.         } /* while (ptr->domain==domain) */
  223.         border++;
  224.     } /* while (border->domain==domain) */
  225. }
  226.  
  227. /* ==========================================================
  228. ** = Routinen zum Vergleich mit schon berechneten Bereichen =
  229. ** ==========================================================
  230. */
  231.  
  232. char find_last_domain(border_typ *start,border_typ *border)
  233. {
  234.     /* sucht den Bereich, in dem sich (border->x/border->y)
  235.     ** das letzte Mal befunden hat. Gibt es keinen, wird
  236.     ** 0 zurueckgegeben, ansonsten die Nummer des Bereiches.
  237.     */
  238.     border_typ *ptr=start;
  239.     while ((ptr<last_border_anz) &&
  240.            ((border->x!=ptr->x) || (border->y!=ptr->y)))
  241.            ptr++;
  242.     if (ptr>=last_border_anz) return 0;
  243.     return ptr->domain;
  244. }
  245.  
  246. char find_new_domain(border_typ *start,border_typ *last_border)
  247. {
  248.     /* sucht den Bereich, in dem sich (last_border->x/last_border->y)
  249.     ** diesmal befindet und gibt seine Nummer zurueck. Gibt es ihn
  250.     ** nicht, eine 0.
  251.     */
  252.     border_typ *ptr=start;
  253.     while ((ptr<border_anz) &&
  254.            ((last_border->x!=ptr->x) || (last_border->y!=ptr->y)))
  255.           ptr++;
  256.     if (ptr>=border_anz) return 0;
  257.     return ptr->domain;
  258. }
  259.  
  260. char look_for_old_domain(border_typ *border,char domain)
  261. {
  262.     /* sucht, ob sich der Bereich domain auch in last_border_arr
  263.     ** befindet. Dazu muessen alle Felder in domain auch in der
  264.     ** gleichen last_domain liegen, und alle Felder dieser
  265.     ** last_domain in domain. Ist dem so, wird die last_domain
  266.     ** zurueckgegeben, sonst 0.
  267.     ** Es kann nicht davon ausgegangen werden, dass die Felder in
  268.     ** beiden Bereichen in der gleichen Reihenfolge liegen, was
  269.     ** den Vergleich etwas kompliziert.
  270.     */
  271.     border_typ *ptr=border,*start_of_last_domain;
  272.     char last_domain;
  273.     if (last_border_anz-last_border_arr==0) return 0;
  274.     if ((last_domain=find_last_domain(last_border_arr,ptr))==0) return 0;
  275.     start_of_last_domain=last_border_arr;
  276.     while (start_of_last_domain->domain!=last_domain)
  277.       start_of_last_domain++;
  278.     do { ptr++;
  279.     } while ((ptr<border_anz) && (ptr->domain==domain) &&
  280.              (last_domain==find_last_domain(start_of_last_domain,ptr)));
  281.     if ((ptr<border_anz) && (ptr->domain==domain)) return 0;
  282.     ptr=last_border_arr;
  283.     while ((ptr->domain!=last_domain) && (ptr<last_border_anz)) ptr++;
  284.     if (ptr>=last_border_anz) return 0;
  285.     while ((ptr<last_border_anz) && (ptr->domain==last_domain) &&
  286.            (domain==find_new_domain(border,ptr)))
  287.           ptr++;
  288.     if ((ptr<last_border_anz) && (ptr->domain==last_domain)) return 0;
  289.     return last_domain;
  290. }
  291.  
  292. void init_border()
  293. {
  294.     border_typ *border;
  295.     int x,y;
  296.     char domain,last_domain;
  297.     border_anz=border_arr;x=-1;y=0;
  298.     while (find_next(&x,&y)) /* create border list */
  299.     {
  300.         border_anz->x=x;border_anz->y=y;border_anz->domain=0;
  301.         border_anz++;
  302.     }
  303.     if (border_anz==border_arr) return;
  304.     domain=0;border=border_arr; /* sort border_arr in Bereiche */
  305.     do {
  306.         domain++;
  307.         if (domain==CHAR_MAX)
  308.         { /* this will never occur, but I can cope with it ;-> */
  309.           border_typ *ptr=border;
  310.           while (ptr<border_anz) {border->domain=domain;ptr++;}
  311.         } else find_domains(border,domain);
  312.         if ((last_domain=look_for_old_domain(border,domain))==0)
  313.         { /* Bereich ist neu */
  314.             min(domain)=INT_MAX;max(domain)=INT_MIN;
  315.         } else
  316.         { /* Bereich war schon mal da */
  317.             min(domain)=last_min(last_domain);
  318.             max(domain)=last_max(last_domain);
  319.         }
  320.         find_testmode(border,domain);
  321.         while ((border->domain==domain) && (border<border_anz)) border++;
  322.     } while (border<border_anz);
  323. }
  324.  
  325. void exit_border()
  326. {
  327.     /* Speichert die erhaltenen Ergebnisse in last_border_arr
  328.     ** bzw in lastminmax ab.
  329.     */
  330.     border_typ *b=last_border_arr;int *i=lastminmax;
  331.     last_border_arr=border_arr;border_arr=b;last_border_anz=border_anz;
  332.     lastminmax=minmax;minmax=i;
  333. }
  334.  
  335. /* Konstanten fuer die Speicherung der Belegungen */
  336. #define h_MASK 192
  337. #define h_EVERYTHING 0
  338. #define h_NOMINE 64
  339. #define h_MINE 128
  340. #define h_UNKNOWN 192
  341.  
  342. int otest_if_possible(border_typ *border_ptr)
  343. {
  344.     /* Testet, ob die Wahl dieses Feldes gegen Informationen
  345.     ** der Nachbarfelder verstoesst.
  346.     ** Diese Funktion wurde aus Geschwindigkeitsgruenden
  347.     ** vollsaendig in Assembler umgesetzt. Der C-Code dient
  348.     ** nur noch der Illustration der Arbeitsweise.
  349.     */
  350.     char d0,d1,mines,marks,x1,y1;
  351.     for (d0=0;d0<8;d0++)
  352.     {
  353.         x1=border_ptr->x+off[d0][0];
  354.         y1=border_ptr->y+off[d0][1];
  355.         if (in_playground(x1,y1) && !(feld[x1][y1] & CLOSED))
  356.         {
  357.             mines=0;marks=0;
  358.             for (d1=0;d1<8;d1++)
  359.             {
  360.                 char x2=x1+off[d1][0],y2=y1+off[d1][1];
  361.                 if (in_playground(x2,y2))
  362.                 {
  363.                     register char f=feld[x2][y2];
  364.                     if (f & MINE) mines++;
  365.                     if (f & MARK) marks++;
  366.                 }
  367.             }
  368.             if (marks>mines) return FALSE;
  369.             if (marks+((border_ptr->test >> d0*4) & 0xF)<mines) return FALSE;
  370.             /*if ((border_ptr->test & (1 << d0))!=0)
  371.                  { if (marks>mines) return FALSE; }
  372.             else { if (marks!=mines) return FALSE; }*/
  373.         }
  374.     }
  375.     return(TRUE);
  376. }
  377.  
  378.  
  379. /* die Asseblerversion von test_if_possible
  380. ** Bei Bedarf kann das Makro in
  381. ** #define ctest_if_possible(b) otest_if_possible(b)
  382. ** geaendert werden. Dann wird wieder die C-Routine benutzt.
  383. */
  384. #include "HintA.h"
  385. #define ctest_if_possible(b) test_if_possible(b,XMAX,YMAX,feld)
  386. /*#define ctest_if_possible(b) otest_if_possible(b)*/
  387.  
  388. /* Rueckgabewerte der Rekursionsroutinen */
  389. #define p_POSSIBLE TRUE
  390. #define p_IMPOSSIBLE FALSE
  391.  
  392. char permutate1(border_typ *border,int mine_anz,char domain)
  393. {
  394.     /* Rekursion mit Abspeichernung der Minimal- und
  395.     ** Maximalwerte, ohne Markenbegrenzung.
  396.     */
  397.     char x,y;
  398.     char p1=p_IMPOSSIBLE,p2=p_IMPOSSIBLE,f1,f2;
  399.     if ((border->domain!=domain) || (border>=border_anz))
  400.     {
  401.       if (mine_anz>max(domain)) max(domain)=mine_anz;
  402.       if (mine_anz<min(domain)) min(domain)=mine_anz;
  403.       return p_POSSIBLE;
  404.     }
  405.     x=border->x;y=border->y;
  406.     if (ctest_if_possible(border)) p1=permutate1(border+1,mine_anz,domain);
  407.     feld[x][y]|=MARK;
  408.     if (ctest_if_possible(border)) p2=permutate1(border+1,mine_anz+1,domain);
  409.     feld[x][y]&=~MARK;
  410.     f1=feld[x][y] & h_MASK;f2=feld[x][y] & ~h_MASK;
  411.     if (p1==p_POSSIBLE)
  412.     {
  413.       if ((f1==h_NOMINE) || (f1==h_EVERYTHING)) f1=h_NOMINE;
  414.       else f1=h_UNKNOWN;
  415.     }
  416.     if (p2==p_POSSIBLE)
  417.     {
  418.       if ((f1==h_MINE) || (f1==h_EVERYTHING)) f1=h_MINE;
  419.       else f1=h_UNKNOWN;
  420.     }
  421.     feld[x][y]=f2 | f1;
  422.     return(p1 | p2);
  423. }
  424.  
  425. char permutate0(border_typ *border,int mine_anz,char domain,char percent,char inc)
  426. {
  427.     /* Rekursion mit Abspeichernung der Minimal- und
  428.     ** Maximalwerte, ohne Markenbegrenzung und als
  429.     ** besonderes Schmankerl fuer den ungeduldigen
  430.     ** Spieler mit Prozentanzeige bei der Sanduhr.
  431.     */
  432.     char x,y;
  433.     char p1=p_IMPOSSIBLE,p2=p_IMPOSSIBLE,f1,f2;
  434.     if ((border->domain!=domain) || (border>=border_anz))
  435.     {
  436.       if (mine_anz>max(domain)) max(domain)=mine_anz;
  437.       if (mine_anz<min(domain)) min(domain)=mine_anz;
  438.       return p_POSSIBLE;
  439.     }
  440.     x=border->x;y=border->y;
  441.     hourglass_percentage(percent);
  442.     if (ctest_if_possible(border))
  443.     {
  444.         if (inc<10) p1=permutate1(border+1,mine_anz,domain);
  445.         else p1=permutate0(border+1,mine_anz,domain,percent,inc/2);
  446.     }
  447.     hourglass_percentage(percent+inc);
  448.     feld[x][y]|=MARK;
  449.     if (ctest_if_possible(border))
  450.     {
  451.         if (inc<10) p2=permutate1(border+1,mine_anz+1,domain);
  452.         else p2=permutate0(border+1,mine_anz+1,domain,percent+inc,inc/2);
  453.     }
  454.     feld[x][y]&=~MARK;
  455.     f1=feld[x][y] & h_MASK;f2=feld[x][y] & ~h_MASK;
  456.     if (p1==p_POSSIBLE)
  457.     {
  458.       if ((f1==h_NOMINE) || (f1==h_EVERYTHING)) f1=h_NOMINE;
  459.       else f1=h_UNKNOWN;
  460.     }
  461.     if (p2==p_POSSIBLE)
  462.     {
  463.       if ((f1==h_MINE) || (f1==h_EVERYTHING)) f1=h_MINE;
  464.       else f1=h_UNKNOWN;
  465.     }
  466.     feld[x][y]=f2 | f1;
  467.     return(p1 | p2);
  468. }
  469.  
  470. char permutate2(border_typ *border,int mine_anz)
  471. {
  472.     /* Rekursion mit Markenbegrenzung, ohne Feststellung
  473.     ** der Minimal- und Maximalwerte und ohne Prozentausgabe.
  474.     ** Die Rekursion laeuft ueber das ganze border_arr, das
  475.     ** aber gegen Spielende, wenn diese Rekursion benutzt ist,
  476.     ** hoffentlich so klein ist, dass es keine merkliche
  477.     ** Rechenzeit beansprucht.
  478.     */
  479.     char x,y;
  480.     char p1=p_IMPOSSIBLE,p2=p_IMPOSSIBLE,f1,f2;
  481.     if (border>=border_anz)
  482.        {
  483.          if (mines_left+fields_left-(border_anz-border_arr)>=mine_anz)
  484.            return p_POSSIBLE; else return p_IMPOSSIBLE;
  485.        }
  486.     x=border->x;y=border->y;
  487.     if (ctest_if_possible(border))
  488.         p1=permutate2(border+1,mine_anz);
  489.     if (mine_anz>0)
  490.     {
  491.         feld[x][y]|=MARK;
  492.         if (ctest_if_possible(border)) p2=permutate2(border+1,mine_anz-1);
  493.         feld[x][y]&=~MARK;
  494.     }
  495.     f1=feld[x][y] & h_MASK;f2=feld[x][y] & ~h_MASK;
  496.     if (p1==p_POSSIBLE)
  497.     {
  498.       if ((f1==h_NOMINE) || (f1==h_EVERYTHING)) f1=h_NOMINE;
  499.       else f1=h_UNKNOWN;
  500.     }
  501.     if (p2==p_POSSIBLE)
  502.     {
  503.       if ((f1==h_MINE) || (f1==h_EVERYTHING)) f1=h_MINE;
  504.       else f1=h_UNKNOWN;
  505.     }
  506.     feld[x][y]=f2 | f1;
  507.     return(p1 | p2);
  508. }
  509.  
  510. /* ein Hinweis */
  511. void hint_it(void)
  512. {
  513.     char x,y,p=0,domain;
  514.     int closed_fields_without_border,max_mines,min_mines;
  515.     border_typ *border,*ptr;
  516.     os_error nrf={0,"negative rest fields !"};
  517.     /* Suche nach einem falschen Zug */
  518.     border_anz=border_arr;
  519.     for (x=0;x<XMAX;x++)
  520.         for (y=0;y<YMAX;y++)
  521.             if (move_wrong(x,y))
  522.             {border_anz->x=x;border_anz->y=y;border_anz++;};
  523.     if (border_anz!=border_arr)
  524.     {
  525.         wimp_window_state w;
  526.         wimp_icon *i=hint_window.window->icons;
  527.         strcpy(i[0].data.indirected_text.text,err_msg1);
  528.         strcpy(i[1].data.indirected_text.text,err_msg2);
  529.         hint_index=2;
  530.         w.w = hint_window.w ;
  531.         wimp_get_window_state(&w);
  532.         set_mouse_box(&w.visible);
  533.         w.next=wimp_TOP;
  534.         wimp_open_window((wimp_open *)&w);
  535.         return;
  536.     }
  537.     /* Suche nach einem offensichtlichen Zug */
  538.     border_anz=border_arr;
  539.     for (x=0;x<XMAX;x++)
  540.         for (y=0;y<YMAX;y++)
  541.             if (move_obvious(x,y))
  542.             {border_anz->x=x;border_anz->y=y;border_anz++;};
  543.     if (border_anz!=border_arr)
  544.     {
  545.         wimp_window_state w;
  546.         wimp_icon *i=hint_window.window->icons;
  547.         strcpy(i[0].data.indirected_text.text,hint_msg1);
  548.         strcpy(i[1].data.indirected_text.text,hint_msg2);
  549.         hint_index=1;
  550.         w.w = hint_window.w ;
  551.         wimp_get_window_state(&w);
  552.         set_mouse_box(&w.visible);
  553.         w.next=wimp_TOP;
  554.         wimp_open_window((wimp_open *)&w);
  555.         return;
  556.     }
  557.     /* Suche nach einer eindeutigen Schlussfolgerung */
  558.     init_border();
  559.     if (border_anz==border_arr)
  560.     { /* Wenn es keinen Rand gibt, kriegt er einen Tip */
  561.         wimp_window_state s;
  562.         ptr=border_arr;
  563.         for (x=0;x<XMAX;x++) for (y=0;y<YMAX;y++)
  564.          if ((feld[x][y] & CLOSED) && !(feld[x][y] & MARK)) {ptr->x=x;ptr->y=y;ptr++;}
  565.         border_anz=ptr;
  566.         hint_choose=TRUE;
  567.         s.w = hint_choose_window.w ;
  568.         wimp_get_window_state(&s);
  569.         s.next=wimp_TOP;
  570.         wimp_open_window((wimp_open *)&s);
  571.         return;
  572.     }
  573.     border=border_arr;domain=1;max_mines=0;min_mines=0;
  574.     hourglass_on();
  575.     do {
  576.         if (max(domain)==INT_MIN)
  577.         {
  578.             for (ptr=border;ptr->domain==domain;ptr++)
  579.                 feld[ptr->x][ptr->y]&=~h_MASK;
  580.             permutate0(border,0,domain,0,50);
  581.         }
  582.         max_mines+=max(domain);min_mines+=min(domain);
  583.         while ((border->domain==domain) && (border<border_anz)) border++;
  584.         domain++;
  585.     } while (border<border_anz);
  586.     hourglass_off();
  587.     closed_fields_without_border=mines_left+fields_left - (border_anz-border_arr);
  588.     if (closed_fields_without_border<0) wimp_report_error(&nrf,2,"Mines !");
  589.     if ((max_mines>mines_left) ||
  590.         (closed_fields_without_border<mines_left-min_mines))
  591.         {
  592.           for (ptr=border_arr;ptr<border_anz;ptr++)
  593.             feld[ptr->x][ptr->y]&=~h_MASK;
  594.           permutate2(border_arr,mines_left);
  595.           if (max_mines>mines_left) max_mines=mines_left;
  596.         }
  597.     if ((closed_fields_without_border>0) &&
  598.         ((min_mines==mines_left) ||
  599.          (closed_fields_without_border==mines_left-max_mines)))
  600.     {
  601.         wimp_window_state s;
  602.         wimp_icon *i=hint_window.window->icons;
  603.         strcpy(i[0].data.indirected_text.text,hint_msg1);
  604.         strcpy(i[1].data.indirected_text.text,hint_msg2);
  605.         hint_index=3;
  606.         s.w = hint_window.w ;
  607.         wimp_get_window_state(&s);
  608.         set_mouse_box(&s.visible);
  609.         s.next=wimp_TOP;
  610.         wimp_open_window((wimp_open *)&s);
  611.         return;
  612.     }
  613.     for (border=border_arr;border<border_anz;border++)
  614.     {
  615.         register unsigned char d=feld[border->x][border->y] & h_MASK;
  616.         if ((d==h_NOMINE) || (d==h_MINE)) p++;
  617.     }
  618.     if (p!=0)
  619.     {
  620.         wimp_window_state s;
  621.         wimp_icon *i=hint_window.window->icons;
  622.         strcpy(i[0].data.indirected_text.text,clue_msg1);
  623.         strcpy(i[1].data.indirected_text.text,clue_msg2);
  624.         hint_index=0;
  625.         s.w = hint_window.w ;
  626.         wimp_get_window_state(&s);
  627.         set_mouse_box(&s.visible);
  628.         s.next=wimp_TOP;
  629.         wimp_open_window((wimp_open *)&s);
  630.         return;
  631.     }
  632.     {
  633.       wimp_window_state s;
  634.       hint_choose=TRUE;
  635.       s.w = hint_choose_window.w; 
  636.       wimp_get_window_state(&s);
  637.       s.next=wimp_TOP;
  638.       wimp_open_window((wimp_open *)&s);
  639.     }
  640. }
  641.  
  642. void give_hint(void)
  643. {
  644.   char d,x,y;
  645.   border_typ border=border_arr[rand() % (border_anz-border_arr)];
  646.   for (d=0;d<8;d++)
  647.   {
  648.       x=border.x+off[d][0];y=border.y+off[d][1];
  649.       if ((x>=0) && (x<XMAX) && (y>=0) && (y<YMAX) &&
  650.           (feld[x][y] & CLOSED) && !(feld[x][y] & MARK))
  651.           draw_sprite(x,y,questionmark.id);
  652.   }
  653.  
  654. }
  655.  
  656. void give_no_hint(void)
  657. {
  658. }
  659.  
  660. void give_clue(void)
  661. {
  662.   char f;
  663.   border_typ *border;
  664.   do {
  665.      border=&border_arr[rand() % (border_anz-border_arr)];
  666.      f=feld[border->x][border->y] & h_MASK;
  667.   } while ((f!=h_NOMINE) && (f!=h_MINE));
  668.   draw_sprite(border->x,border->y,questionmark.id);
  669.   exit_border();
  670. }
  671.  
  672. void give_no_clue(void)
  673. {
  674.   exit_border();
  675. }
  676.  
  677. void give_err(void)
  678. {
  679.   border_typ border=border_arr[rand() % (border_anz-border_arr)];
  680.   draw_sprite(border.x,border.y,nomine.id);
  681. }
  682.  
  683. void give_no_err(void)
  684. {
  685. }
  686.  
  687. void give_count(void)
  688. {
  689.   int x,y,d,c;
  690.   border_anz=border_arr;
  691.   for (x=0;x<XMAX;x++) for (y=0;y<YMAX;y++)
  692.   {
  693.     c=0;for (d=0;d<8;d++)
  694.      if ((in_playground(x+off[d][0],y+off[d][1])) &&
  695.           (!(feld[x+off[d][0]][y+off[d][1]] & CLOSED))) c++;
  696.     if (c==0) {border_anz->x=x;border_anz->y=y;border_anz++;}
  697.   }
  698.   border_anz=&border_arr[rand() % (border_anz-border_arr)];
  699.   draw_sprite(border_anz->x,border_anz->y,questionmark.id);
  700. }
  701.  
  702. void give_no_count(void)
  703. {
  704. }
  705.  
  706. void hint_click(wimp_block *b)
  707. {if(b->pointer.w == hint_window.w)
  708.  {if (b->pointer.i==2)
  709.    {switch (hint_index)
  710.       {case 0 : give_clue();break;
  711.        case 1 : give_hint();break;
  712.        case 2 : give_err();break;
  713.        case 3 : give_count();break;
  714.       }
  715.     unnecessary_hints+=1;
  716.     wimp_close_window(hint_window.w);
  717.     set_mouse_box_screen();
  718.    }
  719.   if((b->pointer.i==3) || (b->pointer.buttons & 2))
  720.    {switch (hint_index)
  721.       {case 0 : give_no_clue();break;
  722.        case 1 : give_no_hint();break;
  723.        case 2 : give_no_err();break;
  724.        case 3 : give_no_count();break;
  725.       }
  726.     unnecessary_hints+=1;
  727.     wimp_close_window(hint_window.w);
  728.     set_mouse_box_screen();
  729.    }
  730.  }
  731. }
  732.  
  733. void hint_choose_handler(int event,wimp_block *b,void *handle)
  734. {
  735.     switch (event)
  736.     {
  737.      case wimp_OPEN_WINDOW_REQUEST:
  738.         wimp_open_window(&(b->open));
  739.         break;
  740.       default : break;
  741.     }
  742. }
  743.  
  744. int hint_choose_done(int x, int y,bits *button)
  745. {
  746.   border_typ *ptr=border_arr;
  747.   if (!hint_choose) return FALSE;
  748.   while (((ptr->x!=x) || (ptr->y!=y)) && (ptr<border_anz)) ptr++;
  749.   if (ptr>=border_anz) {*button=0;return FALSE;}
  750.   wimp_close_window(hint_choose_window.w);
  751.   if (feld[x][y] & MINE) *button=wimp_CLICK_ADJUST; else *button=wimp_CLICK_SELECT;
  752.   hint_choose=FALSE;
  753.   exit_border();
  754.   return TRUE;
  755. }
  756.  
  757. int hint_init(void)
  758. {loadwin(&hint_window,"Hint");
  759.  werr(xwimp_create_window(hint_window.window,&hint_window.w)) ;
  760.  loadwin(&hint_choose_window,"Hintchoose");
  761.  werr(xwimp_create_window(hint_choose_window.window,&hint_choose_window.w)) ;
  762.  if ((border_arr=border_anz=malloc(XMAX*YMAX*sizeof(border_typ)))==0)
  763.      return FALSE;
  764.  if ((last_border_arr=last_border_anz=malloc(XMAX*YMAX*sizeof(border_typ)))==0)
  765.      return FALSE;
  766.  if ((minmax=malloc(512*sizeof(int)))==0) return FALSE;
  767.  if ((lastminmax=malloc(512*sizeof(int)))==0) return FALSE;
  768.  return TRUE;
  769. }
  770.  
  771. void hint_new_game(void)
  772. {
  773.   unnecessary_hints=0;
  774.   if (hint_choose) wimp_close_window(hint_choose_window.w);
  775.   hint_choose=FALSE;
  776. }
  777.  
  778. void hint_exit(void)
  779. {
  780.     free(border_anz);
  781.     free(last_border_anz);
  782.     free(minmax);
  783.     free(lastminmax);
  784. }
  785.